#!/usr/bin/python

import pprint
import math

from sys import argv

# Some globals
diceSides = 6
debug = False

pp = pprint.PrettyPrinter(indent=4)

def getProbDicts(params):

    # Obtain a dict of all possible outcomes
    outcomes = getRawOutcomes(params['atkDice'])

    # Determine the probabilities of specific MoS values
    successes =  getRangeResults(params, outcomes)

    # Evaluate the damage result of the MoS values
    damageDict = evaluateResults(params, successes)

def evaluateResults(params, outcomes):
    print "Evaluated %iD%i+%i vs. %i for damage %i vs. armor %i (overkill %i)" % (
        params['atkDice'], diceSides, params['atkMod'],
        params['threshold'],
        params['dam'], params['armor'], params['boxes'] * params['armor']
        ),
    print ""

    dam = params['dam']
    armor = params['armor']
    numBoxes = params['boxes']
    results = {}
    for x in outcomes:
        # x is a MoS
        prob = outcomes[x]
        if debug:
            print "MoS %+i prob = %2.3f" % (x, prob)

        damage = dam * float(x)
        boxes = math.floor(damage / armor)
        if debug:
            print "Boxes %i occurs %2.3f results from from floor(%f x %i)" % (boxes, prob, dam, x)

        if boxes > numBoxes:
            boxes = numBoxes
            if debug:
                print "Appending OK outcomes (%6.3f) to bucket %i" % (prob, boxes)

        if boxes in results:
            prob = prob + results[boxes] 
        results[boxes] = prob
        
        if x not in results and x <= numBoxes:
            results[x] = 0.0

    print "",
    for y in results:
        print " %i box (%6.3f%%)" % (y, results[y]),
    print ""

def getRangeResults(params, results):
    outcomes = {}
    count = 0
    maxRes = 0

    threshold = params['threshold']
    modifier = params['atkMod']
    isAP = params['isAP']

    for diceRes in results:
        count = count + 1 # loop counter

        res = 0
        if diceRes != 0:
            res = diceRes + modifier
            
        result = res - threshold
        if result < 0:
            result = 0
        elif isAP:
            if debug:
                print "AP applies +%i to %i = %i" % (2, result, result + 2)
            result = result + 2

        if result in outcomes:
            outcomes[result] = outcomes[result] + 1
        else:
            outcomes[result] = 1

        if maxRes < result:
            maxRes = result

        if debug:
            print "ATK (%i + %i) = %i - %i -> MoS %+i" % (
                diceRes, modifier, 
                res, threshold,
                result
                )
    
    checkCount = 0    
    for x in outcomes.iterkeys():
        y = outcomes[x]
        prob = (float(outcomes[x]) / float(count)) * 100.0
        if debug:
            print "  MoS %i has %i occurances (%2.3f)" % (x, y, prob)
        outcomes[x] = prob

        checkCount = checkCount + y
    
    for x in range(0, maxRes + 1, 1):
        if x not in outcomes:
            outcomes[x] = 0

    return outcomes

def getRawOutcomes(numDice):
    outcomes = []
    # Generate the raw list that contains all possible outcomes
    for x in range(1, numDice+1):
        outcomes = appendDiceSides(outcomes, diceSides)
    
    # For each element, reduce it to a pre-modifier value
    results = []
    for x in outcomes:
        res = 0
        for y in x:
            if y == 6 and res >= 6:
                res = res + 1
            elif y > 1 and y > res:
                res = y
        results.append(res)
        if debug:
            print "Raw Outcome of %s has result %i " % (x, res)

    return results

def appendDiceSides(diceList, diceSides):

    if len(diceList) is 0:
        for x in range(1, diceSides+1):
            diceList.append([x])
        return diceList

    newList = []
    for y in diceList:
        # y is an element of list type
        for x in range(1, diceSides+1):
            z = y[:]
            z.append(x)
            newList.append(z)

    return newList

if __name__ == '__main__':
    params = {
        'atkDice': 2,
        'atkMod': 0,
        'threshold': 3,
        'dam' : 8.0,
        'armor': 15.0,
        'boxes': 5.0,
        'isAP' : False
    }

    if len(argv) >= 2:
        params['atkDice'] = int(argv[1])
    if len(argv) >= 3:
        params['atkMod'] = int(argv[2])
    if len(argv) >= 4:
        params['threshold'] = int(argv[3])
    if len(argv) >= 5:
        params['dam'] = float(argv[4])
    if len(argv) >= 6:
        params['armor'] = float(argv[5])
    if len(argv) >= 7:
        params['boxes'] = float(argv[6])
    if len(argv) >= 8:
        params['isAP'] = bool(argv[7])

    probDict = getProbDicts(params)

